﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;

namespace System
{
    /// <summary>
    /// 任务定时器的实现。
    /// </summary>
    public abstract class TimeTask : IDisposable
    {
        /// <summary>
        /// 内部定时时间。
        /// </summary>
        protected readonly Timer InnerTimer = new Timer();

        /// <summary>
        /// 达到间隔时发生。
        /// </summary>
        public event EventHandler Elapsed;

        /// <summary>
        /// 初始化 <see cref="System.TimeTask"/> 的新实例。
        /// </summary>
        public TimeTask()
        {
            this.InnerTimer.Elapsed += new ElapsedEventHandler(InnerTimer_Elapsed);
        }

        void InnerTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.InnerTimer.Stop();
            this.InnerTimer.Interval = this.GetNextInterval();

            if(this.Elapsed != null) this.Elapsed(this, EventArgs.Empty);
            if(this.Enabled) this.InnerTimer.Start();
        }

        private long _Enabled;
        /// <summary>
        /// 获取一个值，指示任务定时器是否已启动。
        /// </summary>
        public bool Enabled
        {
            get
            {
                return GA.LockEquals(ref this._Enabled, 1);
            }
            private set
            {
                System.Threading.Interlocked.Exchange(ref this._Enabled, value ? 1L : 0L);
            }
        }

        /// <summary>
        /// 启动任务定时器。
        /// </summary>
        public void Start()
        {
            if(this.Enabled) return;
            this.InnerTimer.Interval = this.GetFisterInterval();
            this.InnerTimer.Start();
            this.Enabled = true;
        }

        /// <summary>
        /// 停止任务定时器。
        /// </summary>
        public void Stop()
        {
            if(!this.Enabled) return;
            this.Enabled = false;
            this.InnerTimer.Stop();
        }

        /// <summary>
        /// 获取第一次间隔的毫秒数。
        /// </summary>
        /// <returns>返回一个 <see cref="System.Double"/> 值。</returns>
        protected abstract double GetFisterInterval();

        /// <summary>
        /// 获取下一次间隔的毫秒数。
        /// </summary>
        /// <returns>返回一个 <see cref="System.Double"/> 值。</returns>
        protected abstract double GetNextInterval();

        #region IDisposable 成员

        void IDisposable.Dispose()
        {
            this.InnerTimer.Dispose();
        }

        #endregion
    }

    /// <summary>
    /// 以天为周期的任务定时器。
    /// </summary>
    public class DayTimeTask : TimeTask
    {
        private TimeSpan _Interval;
        /// <summary>
        /// 设置或获取定时器的间隔。
        /// </summary>
        public TimeSpan Interval
        {
            get
            {
                return this._Interval;
            }
            set
            {
                this._Interval = value;
            }
        }
        /// <summary>
        /// 设置或获取用户自定义数据。
        /// </summary>
        public object Tag { get; set; }
        /// <summary>
        /// 初始化 <see cref="System.DayTimeTask"/> 的新实例。
        /// </summary>
        /// <param name="interval">定时器的间隔。</param>
        public DayTimeTask(TimeSpan interval)
        {
            this._Interval = interval;
        }

        /// <summary>
        /// 初始化 <see cref="System.DayTimeTask"/> 的新实例。
        /// </summary>
        /// <param name="days">每几天。</param>
        /// <param name="hours">第几小时。</param>
        /// <param name="minutes">第几分钟。</param>
        /// <param name="seconds">第几秒。</param>
        public DayTimeTask(int days, int hours, int minutes, int seconds)
            : this(new TimeSpan(days, hours, minutes, seconds)) { }

        /// <summary>
        /// 获取第一次间隔的毫秒数。
        /// </summary>
        /// <returns>返回一个 <see cref="System.Double"/> 值。</returns>
        protected override double GetFisterInterval()
        {
            if(this._Interval.Days > 0)
            {
                // 定时每 days 天执行一次
                return (DateTime.Now.AddDays(this._Interval.Days).Date
                            .AddHours(this._Interval.Hours)
                            .AddMinutes(this._Interval.Minutes)
                            .AddSeconds(this._Interval.Seconds)
                      - DateTime.Now).TotalMilliseconds;
            }
            else
            {
                return this.GetNextInterval();
            }
        }

        /// <summary>
        /// 获取下一次间隔的毫秒数。
        /// </summary>
        /// <returns>返回一个 <see cref="System.Double"/> 值。</returns>
        protected override double GetNextInterval()
        {
            return this._Interval.TotalMilliseconds;
        }

    }
}
